package remato.client.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.views.properties.IPropertySource;

import com.wgo.bpot.common.removeme.Persistent;

import remato.client.controller.RequirementPlugin;
import remato.client.model.facade.IMenuItemsProvider;
import remato.client.model.facade.IPropertyDefinitionContainer;
import remato.client.model.facade.ModelSystem;
import remato.client.view.editor.IModelFormPart;
import remato.client.view.editor.properties.PropertiesFormPage;
import remato.client.view.editor.usertypes.UsertypesSectionPart;
import remato.client.view.util.ModelItemPropertySource;
import remato.domain.common.PropertyDef;
import remato.domain.common.PropertySet;
import remato.domain.common.RequirementSystem;
import remato.common.domain.helpers.Nameable;
import static remato.client.controller.PrecisePluginImage.IMG_PROPERTY_SET;
/**
 * @author petterei
 *
 * @version $Id: PropertySetWrapper.java,v 1.4 2006-02-19 16:29:37 petterei Exp $
 */
public class PropertySetWrapper extends NodeChild<ModelSystem<PropertySetWrapper>> implements IPropertyDefinitionContainer, IMenuItemsProvider {
	private PropertySet propertySet;
	private Map<PropertyDef, PropertyDefWrapper> propertyDefinitions;
	private List<PropertyDefWrapper> sortedPropertyDefinitions;
	private static PropertySpecification<Persistent> lastUpdatedDate;
	private static final Class PARENT_INTERFACE = RequirementSystem.class;

	static {
		lastUpdatedDate = new PropertySpecification<Persistent>(Configuration.getInstance().getNextPropertyDefSetDefinitionId(), "Last update", PropertyType.DATE) {
			@Override
			protected Object getValue(Persistent persistent) {
				return ((PropertySet)persistent).getUpdatedDate();
			}
			@Deprecated // Read-only value, thus should not be used
			@SuppressWarnings("unused") // Read-only value, thus parameters not used
			@Override
			protected void setValue(Persistent item, Object value) {}
		};
		lastUpdatedDate.setDescription("Date and time of last update of the propertySet.");
		lastUpdatedDate.setPosition(Configuration.getInstance().getNextPropertyDefSetDefinitionPosition());
		lastUpdatedDate.setDefaultValue("0000.00.00 00:00");
		lastUpdatedDate.setReadOnly(true);
	}
	
	/**
	 * Use when created from gui, then set parent.
	 */
	protected PropertySetWrapper(PropertySet propertySet) {
		super(propertySet, PARENT_INTERFACE, null);
		init(propertySet);
	}
	
	/**
	 * Use when created from server.
	 */
	protected PropertySetWrapper(PropertySet propertySet, PropertyDefinitionSetSystemWrapper wrapper) {
		super(propertySet,wrapper, PARENT_INTERFACE, null);
	}
	
	@Override
	protected void init(Nameable nameable){
		this.propertySet = (PropertySet)nameable;
		propertyDefinitions = new Hashtable<PropertyDef, PropertyDefWrapper>();
		sortedPropertyDefinitions = Collections.synchronizedList(new LinkedList<PropertyDefWrapper>());
		initPropertyFromDomainObject(lastUpdatedDate);
	}
	
	/**
	 * @see remato.client.model.ClientModelItem#getSortingOrder()
	 */
	public int getSortingOrder() {
		return Configuration.PROPERTY_DEFINITION_SET_SORT_ORDER;
	}
	
	public synchronized Collection<PropertyDefWrapper> getPopertyDefinitions() {
		Map<PropertyDef, PropertyDefWrapper> newPropertyDefinitions = new Hashtable<PropertyDef, PropertyDefWrapper>();
		List<PropertyDefWrapper> newSortedPropertyDefinitions = Collections.synchronizedList(new LinkedList<PropertyDefWrapper>());
		synchronized (propertyDefinitions) {
			for (PropertyDef def : propertySet.getPropertyDefs()) {
				PropertyDefWrapper  spec = propertyDefinitions.get(def);
				if (null == spec) {
					spec = RequirementPlugin.getInstance().getSession().getWrapperFactory().getWrapper(def);
				}
				newPropertyDefinitions.put(def, spec);
				int index = ((List)propertySet.getPropertyDefs()).indexOf(def);
				newSortedPropertyDefinitions.add(index,spec);
	        }
			propertyDefinitions = newPropertyDefinitions;
			sortedPropertyDefinitions = newSortedPropertyDefinitions;
		}
		return sortedPropertyDefinitions;
	}
	
	public Collection<AbstractPropertySpesification> getAbstractPopertyDefinitions() {
		ArrayList<AbstractPropertySpesification> returnList = new ArrayList<AbstractPropertySpesification>();
		returnList.addAll(getPopertyDefinitions());
		return returnList;
	}
	
	public synchronized void addPropertyDefinition(PropertyDefWrapper definition) {
		propertySet.addPropertyDef(definition.getDomainModelDefinition());
		propertyDefinitions.put(definition.getDomainModelDefinition(), definition);
		sortedPropertyDefinitions.add(definition);
	}
	
	public synchronized void removePropertyDefinition(PropertyDefWrapper definition) {
		propertySet.removePropertyDef(definition.getDomainModelDefinition());
		propertyDefinitions.remove(definition.getDomainModelDefinition());
		sortedPropertyDefinitions.remove(definition);
	}
	
	public synchronized void updatePropertyDefinition(PropertyDefWrapper element) {
		int position = sortedPropertyDefinitions.indexOf(element);
		sortedPropertyDefinitions.remove(element);
		sortedPropertyDefinitions.add(position, element);
	}
	
	public synchronized boolean insertAfter(PropertyDefWrapper insert, PropertyDefWrapper after) {
		if (insert.equals(after)) {
			return false;
		}
		sortedPropertyDefinitions.remove(insert);
		int newIndex = sortedPropertyDefinitions.indexOf(after) + 1;
		sortedPropertyDefinitions.add(newIndex, insert);
		int position = sortedPropertyDefinitions.get(newIndex -1 ).getPosition() + 1;
		for (PropertyDefWrapper spec : sortedPropertyDefinitions.subList(newIndex, sortedPropertyDefinitions.size())) {
			spec.setPosition(position);
			position++;
		}
		return true;
	}
	
	/**
	 * @see remato.client.model.ClientModelItem#getPropertiesFormParts(remato.client.view.editor.properties.PropertiesFormPage, org.eclipse.ui.forms.IManagedForm)
	 */
	@Override
	public List<IModelFormPart> getPropertiesFormParts(PropertiesFormPage page, IManagedForm managedForm) {
		List<IModelFormPart> formParts = super.getPropertiesFormParts(page, managedForm); 
		Composite body = managedForm.getForm().getBody();
		Composite section = managedForm.getToolkit().createComposite(body);
		section.setLayout(new FillLayout());
		formParts.add(new UsertypesSectionPart(page, section));
		return formParts;
	}
	
	@Override
	public Object getAdapter(Class adapter) {
		if (adapter == IPropertySource.class) {
			ModelItemPropertySource propertySource = new ModelItemPropertySource(this);
			propertySource.addAbstractPropertySpesification(lastUpdatedDate);
			return propertySource;
		} 
		return super.getAdapter(adapter);
	}
	
	@Override
	public Image getImage() {
		return IMG_PROPERTY_SET.getImage();
	}

}
